var Game = function(canvasName, difficulty) {


//creates the Stage into the given canvas
    var _stage = new createjs.Stage(canvasName);
    var _score = 0; 
    var _difficulty = difficulty;
    var _maxMana = 100;
    var _mana = _maxMana;
    
    var _started = false;
    var _paused = false;
    
    var _researchCenterHasReceivedPaquetWithPoints = function(points){
        _score+=points*10;
        _mana+= points/2;
        if(_mana > _maxMana){
            _mana = _maxMana;
        }
        _HUD.updateWithScoreAndMana(_score, _mana);
    };
    var _researchCenterDied = function(){
        createjs.Ticker.setPaused(true);
        if(typeof $j != "undefined"){
            displayFormEndGame(_score, _difficulty);
        }else{
            // jQuery n'existe pas.
            alert("Vous avez perdu ! \nScore total : "+_score);
        }
    };
    var _waitingToBeProcessedSpells = new Array();
    

    var _timeElapsedSinceBegining;
    var _remainingTimeBeforeNextSent = -1;
    var _researchCenterNextSent;
    

    // Private instance vars.
    var _canvas = document.getElementById(canvasName);
    var _canvasWidth = _canvas.width;
    var _canvasHeight = _canvas.height;

    var _nodes = new Array();
    var _researchCenters = new Array();
    var _connexions = new Array();
    
    var _packetFactory = new PacketFactory(_stage);
    var _HUD = new HUD(_stage, _canvasWidth, this);

    
    /**
     * Check if the values x or y are not out of canvas.
     */
    var _checkPositions = function(x, y){
        if(x > _canvasWidth && y > _canvasHeight) {
            console.log("Erreur: Un élément a été placé en dehors du canvas. [Largeur et hauteur trop importantes] (x:"+x+"|y:"+y+")");
        } else if(x > _canvasWidth) {
            console.log("Erreur: Un élément a été placé en dehors du canvas. [Largeur trop importante] (x:"+x+"|y:"+y+")");
        } else if(y > _canvasHeight) {
            console.log("Erreur: Un élément a été placé en dehors du canvas. [Hauteur trop importante] (x:"+x+"|y:"+y+")");
        }
        
        if(x < 0 || y < 0){
            console.log("Erreur: Un élément a été placé en dehors du canvas. [Hauteur/Largeur inférieure à zéro] (x:"+x+"|y:"+y+")");
        }
    };
    
    /**
     * Display the current object in the console.
     */
    this.displayConsole = function(){
        console.log(this);
    }

    this.addCommunicationNode = function(x,y){
        _checkPositions(x, y);
        var comNode = new CommunicationNode(x, y, _stage);
        _nodes.push(comNode);
        return comNode;
    };
    this.addResearchCenter = function(x, y, type, health, packetHealth){
        _checkPositions(x, y);
        var center = new ResearchCenter(x, y, health, packetHealth, type, _stage, _researchCenterHasReceivedPaquetWithPoints, _researchCenterDied);
        _researchCenters.push(center);
        return center;
    };
    this.addConnexion = function(node1, node2){
        var cnx = new Connexion(node1, node2, _stage);
        _connexions.push(cnx);
        return cnx;
    };
    this.addSpellToWaitingList = function(spell){
        _waitingToBeProcessedSpells.push(spell);
    };
     
    this.togglePause = function(){
        if(_started){
            if(_paused){
                createjs.Ticker.setPaused(false);
                _paused = false;
            } else {
                createjs.Ticker.setPaused(true);
                _paused = true;
            }
        }
    }
     
    this.start = function(){
        _HUD.updateWithScoreAndMana(0, 100);
        createjs.Ticker.setPaused(false); //unpause the ticker set below
        //_researchCenters[0].sendPacket(200, _packetFactory);
        //_researchCenters[2].sendPacket(100, _packetFactory);
        _timeElapsedSinceBegining = 0;
        SoundEngine.getInstance().startMusic();
        _started = true;
    };
    
    //This is the update loop, called at each frame
    
    
    var _update = function(timeElapsedInMilliseconds){
        _timeElapsedSinceBegining+=timeElapsedInMilliseconds;

        if(_researchCenterNextSent == null){
            var rand = Math.floor((Math.random()* (_researchCenters.length+1)));
            if(rand < _researchCenters.length){ //au cas où random() aurait généré 1 (improbable, mais bon...)
                _researchCenterNextSent = _researchCenters[rand];
            }
            //calculate time and modifing it by 30% (15% more or less)
            var range = 0.3;
            var intervalWithIncreasingDifficulty = _getIntervalFromGloablTime();
            _remainingTimeBeforeNextSent = (Math.random()*range)+(1.0-range/2.0) * intervalWithIncreasingDifficulty;
        }
        
        _remainingTimeBeforeNextSent-=timeElapsedInMilliseconds;
        _researchCenterNextSent.setRemainingTimeBeforeNewPacketSent(_remainingTimeBeforeNextSent);
        
        if(_remainingTimeBeforeNextSent <= 0){
            _researchCenterNextSent.sendPacket(_getPacketSpeedFromGlobalTime(), _packetFactory);
            
            
            for(var rcIndex in _researchCenters){
                var rc = _researchCenters[rcIndex];
                if(rc.getType() == _researchCenterNextSent.getType()){
                    //decrese life a bit on each center with same type
                    if(rc!=_researchCenterNextSent){
                        rc.decreaseHealth(_researchCenterNextSent.getPacketHealth()/4);
                    }
                }
            }
            
            _researchCenterNextSent = null;
        }
        
        for (var s in _waitingToBeProcessedSpells){
            _mana -= _waitingToBeProcessedSpells[s].costInMana();
            if(_mana<0){
                _mana += _waitingToBeProcessedSpells[s].costInMana();
            } else {
                _waitingToBeProcessedSpells[s].processSpell(_researchCenters, _connexions, _nodes);
            }
        }
        if(_waitingToBeProcessedSpells.length > 0){
            _waitingToBeProcessedSpells.splice(0, _waitingToBeProcessedSpells.length);
            _HUD.updateWithScoreAndMana(_score, _mana);
        }
            
        
        //on process les noeuds, connexions et research centers
        for (var n in _nodes){
            _nodes[n].processWaitingPacket();
        }
        
        for (var c in _connexions){
            _connexions[c].processTranslations(timeElapsedInMilliseconds);
        }
        
        for (var rc in _researchCenters){
            _researchCenters[rc].processWaitingPacket();
        }
        
        _stage.update();
    };
    

    var START_EASYNESS = 3;
    var INCREASE_SPEED = 1.8;
    var MINIMUM_INTERVAL = 1.0;
    var DIFFERENCE_BETWEEN_START_AND_END = 10;

    var _getIntervalFromGloablTime = function(){
        var xDiff = (_timeElapsedSinceBegining/1000)/60;
        var loga = Math.log(xDiff+START_EASYNESS);
        var pow = Math.pow(loga, INCREASE_SPEED);
        var intervalInSeconds = (1.0/pow*DIFFERENCE_BETWEEN_START_AND_END)+MINIMUM_INTERVAL;
        console.log("Interval : "+intervalInSeconds);
        return intervalInSeconds*1000;
    }
    
    var _getPacketSpeedFromGlobalTime = function(){
        var timeSinceBeginingInSeconds = _timeElapsedSinceBegining/1000;
        //return ((Math.log(timeSinceBeginingInSeconds)+1)/10)+25
        if(timeSinceBeginingInSeconds < 30){
            return 35;
        } else if (timeSinceBeginingInSeconds < 60){
            return 50;
        } else if (timeSinceBeginingInSeconds < 90){
            return 65;
        } else if (timeSinceBeginingInSeconds < 120){
            return 80;
        } else if (timeSinceBeginingInSeconds < 180){
            return 100;
        } else if (timeSinceBeginingInSeconds < 210){
            return 133;
        } else if (timeSinceBeginingInSeconds < 240){
            return 166;
        } else if (timeSinceBeginingInSeconds < 270){
            return 200;
        } else if (timeSinceBeginingInSeconds < 300){
            return 250;
        } else if (timeSinceBeginingInSeconds < 320){
            return 300;
        } else if (timeSinceBeginingInSeconds < 350){
            return 350;
        } else if (timeSinceBeginingInSeconds < 380){
            return 350;
        } else if (timeSinceBeginingInSeconds < 410){
            return 400;
        } else if (timeSinceBeginingInSeconds < 440){
            return 450;
        } else if (timeSinceBeginingInSeconds < 470){
            return 500;
        } else {
            return 600;
        }
    };   
   
    createjs.Ticker.setFPS(30);
    createjs.Ticker.addListener(_update);
    createjs.Ticker.setPaused(true);
    
    
};

function LoadAssets(){
    ImageEngine.getInstance();//launch the load
    SoundEngine.getInstance();
}